/*!
    \file  onchip_flash.c
    \brief flash driver

    \version 2020-8-4, V1.0.0, firmware for RV300+
*/

/*
    Copyright (c);2019-2022;Wiscom System;

	All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the Wiscom System nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/


#include <stdio.h>
#include "csg_sdk_hal.h"
#include "csg_sdk_soc.h"
#include "onchip_flash.h"
#define SPI_DELAY_TIME_US           500
#define GPIO_SPI_SCK_1    LGPIO_WriteBit(LGPIO,1<<26,1)            /* SCK = 1 */
#define GPIO_SPI_SCK_0    LGPIO_WriteBit(LGPIO,1<<26,0)        /* SCK = 0 */

#define GPIO_SPI_MOSI_1    LGPIO_WriteBit(LGPIO,1<<27,1)            /* MOSI = 1 */
#define GPIO_SPI_MOSI_0    LGPIO_WriteBit(LGPIO,1<<27,0)        /* MOSI = 0 */

#define GPIO_SPI_CS_ON    LGPIO_WriteBit(LGPIO,1<<7,0)            /* CS = 0 */
#define GPIO_SPI_CS_OFF    LGPIO_WriteBit(LGPIO,1<<7,1)        /* CS = 1 */

#define GPIO_SPI_READ_MISO    LGPIO_ReadInputDataBit(LGPIO, 1<<28)    /* 读MISO口线状态 */

#define Dummy_Byte    0xFF    //读取时MISO发送的数据，可以为任意数据
void spi2_iomux_config(void)
{
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_SCK_IOF_OVAL ,0 , QSPI2_SCK_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_CS_IOF_OVAL ,0 , QSPI2_CS_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_DQ_0_IOF_OVAL ,0 , QSPI2_DQ_0_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI2_DQ_0_IOF_IVAL ,0 , QSPI2_DQ_0_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_DQ_1_IOF_OVAL ,0 , QSPI2_DQ_1_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI2_DQ_1_IOF_IVAL ,0 , QSPI2_DQ_1_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_DQ_2_IOF_OVAL ,0 , QSPI2_DQ_2_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI2_DQ_2_IOF_IVAL ,0 , QSPI2_DQ_2_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI2_DQ_3_IOF_OVAL ,0 , QSPI2_DQ_3_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI2_DQ_3_IOF_IVAL ,0 , QSPI2_DQ_3_HS_SEL, 0, 0);
}
void spi6_iomux_config(void)
{
    iomux_ls_iof_oval_cfg(IOMUX_BASE, 137,0 ,1 , 0, 0);
    
    // iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI6_CS_IOF_OVAL ,0 , QSPI6_CS_HS_SEL, 0, 0);
    //CS
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_7_IOF_OVAL,13,LGPIO_IO_PORT_PINS_7_HS_SEL,0,0);
    LGPIO_Output_Enable(LGPIO,1<<7);
    LGPIO_WriteBit(LGPIO,1<<7,1);
    LGPIO_Mode(LGPIO,1<<7,PP);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, 138 ,0 ,1 , 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, 138 ,0 ,1 , 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, 134 ,0 ,1 , 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, 134 ,0 ,1 , 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, 135 ,0 ,1 , 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, 135 ,0 ,1 , 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, 136 ,0 ,1 , 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, 136 ,0 ,1 , 0, 0);
}
void spi0_iomux_config(void)
{
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_SCK_IOF_OVAL ,0 , QSPI0_SCK_HS_SEL, 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_CS_IOF_OVAL ,0 , QSPI0_CS_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_DQ_0_IOF_OVAL ,0 , QSPI0_DQ_0_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI0_DQ_0_IOF_IVAL ,0 , QSPI0_DQ_0_HS_SEL, 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_DQ_1_IOF_OVAL ,0 , QSPI0_DQ_1_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI0_DQ_1_IOF_IVAL ,0 , QSPI0_DQ_1_HS_SEL, 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_DQ_2_IOF_OVAL ,0 , QSPI0_DQ_2_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI0_DQ_2_IOF_IVAL ,0 , QSPI0_DQ_2_HS_SEL, 0, 0);
    
    iomux_ls_iof_oval_cfg(IOMUX_BASE, QSPI0_DQ_3_IOF_OVAL ,0 , QSPI0_DQ_3_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE, QSPI0_DQ_3_IOF_IVAL ,0 , QSPI0_DQ_3_HS_SEL, 0, 0);
}
////////////////////////
void GPIO_spi6_iomux_config(void)
{
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_7_IOF_OVAL,13,LGPIO_IO_PORT_PINS_7_HS_SEL,0,0);
    LGPIO_Output_Enable(LGPIO,1<<7);//CS
    LGPIO_WriteBit(LGPIO,1<<7,1);//CS
    LGPIO_Mode(LGPIO,1<<7,PP);//CS

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_26_IOF_OVAL,137,LGPIO_IO_PORT_PINS_26_HS_SEL,0,0);//SCK
    LGPIO_Output_Enable(LGPIO,1<<26);//SCK
    LGPIO_WriteBit(LGPIO,1<<26,1);//SCK
    LGPIO_Mode(LGPIO,1<<26,PP);//SCK

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_27_IOF_OVAL,138,LGPIO_IO_PORT_PINS_27_HS_SEL,0,0);//MOSI
    LGPIO_Output_Enable(LGPIO,1<<27);//MOSI
    LGPIO_WriteBit(LGPIO,1<<27,1);//MOSI
    LGPIO_Mode(LGPIO,1<<27,PP);//MOSI

    iomux_ls_iof_ival_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_28_IOF_IVAL,134,LGPIO_IO_PORT_PINS_28_HS_SEL,0,0);//MISO
    LGPIO_Input_Enable(LGPIO,1 << 28);//MISO
}
//SPI可以同时读取和写入数据，因此一个函数即可满足要求
uint8_t GPIO_SPI_ReadWriteByte(uint8_t txData)
{
    uint8_t i;
    uint8_t rxData = 0;

    for(i = 0; i < 8; i++)
    {
        GPIO_SPI_SCK_0;
        delay_1us(SPI_DELAY_TIME_US);
        //数据发送
        if(txData & 0x80){
            GPIO_SPI_MOSI_1;
        }else{
            GPIO_SPI_MOSI_0;
        }
        txData <<= 1;
        delay_1us(SPI_DELAY_TIME_US);

        GPIO_SPI_SCK_1;
        delay_1us(SPI_DELAY_TIME_US);
        //数据接收
        rxData <<= 1;
        if(GPIO_SPI_READ_MISO){
            rxData |= 0x01;
        }
        delay_1us(SPI_DELAY_TIME_US);
    }
    GPIO_SPI_SCK_0;

    return rxData;
}

uint8_t GPIO_SPI_ReadByte(void)
{
    return GPIO_SPI_ReadWriteByte(Dummy_Byte);
}

void GPIO_SPI_WriteByte(uint8_t txData)
{
    (void)GPIO_SPI_ReadWriteByte(txData);
}
///////////////////////////////////////////
uint8_t spi_proto = 0;
void SPI_Init(void)
{
    SPI_REG(SPI_REG_SCKMODE) = 0;
    SPI_REG(SPI_REG_FMT) = 0x80000;
    SPI_REG(SPI_REG_FCTRL) = 0;
    SPI_REG(SPI_REG_CSDEF) = 0xFF;
    SPI_REG(SPI_REG_SCKDIV) = 0x07;
    SPI_REG(SPI_REG_CSID) = 1;
    SPI_REG(SPI_REG_CSMODE) = 3;

    spi_proto = 0;

    SPI_REG(SPI_REG_FCTRL) = 0;
    SPI_REG(SPI_REG_FORCE) = 3;
}

void SPI_WriteByte(uint8_t TxData)
{
    SPI_REG(SPI_REG_FMT) = 0x80008;
    while(SPI_REG(SPI_REG_STATUS) & (0x1 << 4));
    SPI_REG(SPI_REG_TXFIFO) = TxData;
    while(SPI_REG(SPI_REG_STATUS) & (0x1));
}

uint8_t SPI_ReadByte(void)
{
    SPI_REG(SPI_REG_FMT) = 0x80000 | spi_proto;
    SPI_REG(SPI_REG_TXFIFO) = 0x00;
    while(SPI_REG(SPI_REG_STATUS) & (0x1 << 5));
    return (uint8_t)(SPI_REG(SPI_REG_RXFIFO) & 0xff);
}

void SPI_ReadJEDEC(void)
{
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        
        SPI_WriteByte(0x9F);
        for(int i = 0; i < 3; i++) {
            printf("JEDEC[%d]:%#x\n", i ,SPI_ReadByte());
        }
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(0x9F);
        for(int i = 0; i < 3; i++) {
            printf("JEDEC[%d]:%#x\n", i ,GPIO_SPI_ReadByte());
        }
        GPIO_SPI_CS_OFF;
    }
	
}

void SPI_Wip(void)
{
    uint8_t temp = 0;
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(0x05);
        do {
            temp = SPI_ReadByte() & 0x1;
        }while(temp);
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(0x05);
        do {
            temp = GPIO_SPI_ReadByte() & 0x1;
        }while(temp);
        GPIO_SPI_CS_OFF;
    }
}

void SPI_WriteEnable(void)
{
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(0x06);
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(0x06);
        GPIO_SPI_CS_OFF;
    }
}

void SPI_Erase(uint8_t cmd, uint32_t addr)
{
    SPI_WriteEnable();
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(cmd);
        SPI_WriteByte(addr >> 16);
        SPI_WriteByte(addr >> 8);
        SPI_WriteByte(addr);
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(cmd);
        GPIO_SPI_WriteByte(addr >> 16);
        GPIO_SPI_WriteByte(addr >> 8);
        GPIO_SPI_WriteByte(addr);
        GPIO_SPI_CS_OFF;
    }
    SPI_Wip();
}

void SPI_PageWrite(uint8_t cmd, uint8_t* buf, uint32_t addr)
{
    SPI_WriteEnable();
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(cmd);
        SPI_WriteByte(addr >> 16);
        SPI_WriteByte(addr >> 8);
        SPI_WriteByte(addr);
        for(int i = 0; i < 256; i++) {
            SPI_WriteByte(buf[i]);
        }
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(cmd);
        GPIO_SPI_WriteByte(addr >> 16);
        GPIO_SPI_WriteByte(addr >> 8);
        GPIO_SPI_WriteByte(addr);
        for(int i = 0; i < 256; i++) {
            GPIO_SPI_WriteByte(buf[i]);
        }
        GPIO_SPI_CS_OFF;
    }
    SPI_Wip();
}

void SPI_PageRead(uint8_t cmd, uint8_t* buf, uint32_t addr)
{
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(cmd);
        SPI_WriteByte(addr >> 16);
        SPI_WriteByte(addr >> 8);
        SPI_WriteByte(addr);
        SPI_WriteByte(00);
        for(int i = 0; i < 256; i++) {
            buf[i] = SPI_ReadByte();
        }
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(cmd);
        GPIO_SPI_WriteByte(addr >> 16);
        GPIO_SPI_WriteByte(addr >> 8);
        GPIO_SPI_WriteByte(addr);
        GPIO_SPI_WriteByte(00);
        for(int i = 0; i < 256; i++) {
            buf[i] = GPIO_SPI_ReadByte();
        }
        GPIO_SPI_CS_OFF;
    }
}
/*!
    \brief      initialize SPI0 GPIO and parameter
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_flash_init(void)
{
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            qspi2_clk_en(ENABLE);
            qspi2_set_rst(DISABLE);
            qspi2_set_rst(ENABLE);

            spi2_iomux_config();
        }
        else
        {
            qspi6_clk_en(ENABLE);
            qspi6_set_rst(DISABLE);
            qspi6_set_rst(ENABLE);

            spi6_iomux_config();
        }
        SPI_Init();
    }
    else
    {

        GPIO_spi6_iomux_config();
    }
}
/*!
    \brief      erase the specified flash sector
    \param[in]  sector_addr: address of the sector to erase
    \param[out] none
    \retval     none
*/
void spi_flash_sector_erase(uint32_t sector_addr)
{
    SPI_WriteEnable();
    if (USE_SPI_IO == 1)
    {
        sector_addr=sector_addr+ONCHIP_FLASH_OFFSET;
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        SPI_WriteByte(0x20);
        SPI_WriteByte(sector_addr >> 16);
        SPI_WriteByte(sector_addr >> 8);
        SPI_WriteByte(sector_addr);
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        GPIO_SPI_WriteByte(0x20);
        GPIO_SPI_WriteByte(sector_addr >> 16);
        GPIO_SPI_WriteByte(sector_addr >> 8);
        GPIO_SPI_WriteByte(sector_addr);
        GPIO_SPI_CS_OFF;
    }
    SPI_Wip();
}
/*!
    \brief      write more than one byte to the flash
    \param[in]  pbuffer: pointer to the buffer
    \param[in]  write_addr: flash's internal address to write
    \param[in]  num_byte_to_write: number of bytes to write to the flash
    \param[out] none
    \retval     none
*/
void spi_flash_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
    /* enable the write access to the flash */
    SPI_WriteEnable();

    /* select the flash: chip select low */
    if (USE_SPI_IO == 1)
    {
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        /* send "write to memory" instruction */
        SPI_WriteByte(0x02);
        /* send write_addr high nibble address byte to write to */
        SPI_WriteByte(write_addr >> 16);
        /* send write_addr medium nibble address byte to write to */
        SPI_WriteByte(write_addr >> 8);
        /* send write_addr low nibble address byte to write to */
        SPI_WriteByte(write_addr);

        /* while there is data to be written on the flash */
        //printf("flash one time byte:%d\r\n", num_byte_to_write);
        for(int i = 0; i < num_byte_to_write; i++) {
            SPI_WriteByte(*(pbuffer+i));
        }
        /* deselect the flash: chip select high */
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        /* send "write to memory" instruction */
        GPIO_SPI_WriteByte(0x02);
        /* send write_addr high nibble address byte to write to */
        GPIO_SPI_WriteByte(write_addr >> 16);
        /* send write_addr medium nibble address byte to write to */
        GPIO_SPI_WriteByte(write_addr >> 8);
        /* send write_addr low nibble address byte to write to */
        GPIO_SPI_WriteByte(write_addr);

        /* while there is data to be written on the flash */
        //printf("flash one time byte:%d\r\n", num_byte_to_write);
        for(int i = 0; i < num_byte_to_write; i++) {
            GPIO_SPI_WriteByte(*(pbuffer+i));
        }
        /* deselect the flash: chip select high */
        GPIO_SPI_CS_OFF;
    }

    /* wait the end of flash writing */
    SPI_Wip();
}
/*!
    \brief      write block of data to the flash
    \param[in]  pbuffer: pointer to the buffer
    \param[in]  write_addr: flash's internal address to write
    \param[in]  num_byte_to_write: number of bytes to write to the flash
    \param[out] none
    \retval     none
*/
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
    uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;
    if (USE_SPI_IO == 1)
    {
        write_addr=write_addr+ONCHIP_FLASH_OFFSET;
    }
    addr          = write_addr % SPI_FLASH_PAGE_SIZE;
    count         = SPI_FLASH_PAGE_SIZE - addr;
    num_of_page   = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
    num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;

     /* write_addr is SPI_FLASH_PAGE_SIZE aligned  */
    if(0 == addr){
        /* num_byte_to_write < SPI_FLASH_PAGE_SIZE */
        if(0 == num_of_page)
            spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
        /* num_byte_to_write > SPI_FLASH_PAGE_SIZE */
        else{
            while(num_of_page--){
                spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
                write_addr += SPI_FLASH_PAGE_SIZE;
                pbuffer += SPI_FLASH_PAGE_SIZE; 
            }
            spi_flash_page_write(pbuffer,write_addr,num_of_single);
        }
    }else{
        /* write_addr is not SPI_FLASH_PAGE_SIZE aligned  */
        if(0 == num_of_page){
            /* (num_byte_to_write + write_addr) > SPI_FLASH_PAGE_SIZE */
            if(num_of_single > count){
                temp = num_of_single - count;
                spi_flash_page_write(pbuffer,write_addr,count);
                write_addr += count;
                pbuffer += count;
                spi_flash_page_write(pbuffer,write_addr,temp);
            }else
                spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
        }else{
            /* num_byte_to_write > SPI_FLASH_PAGE_SIZE */
            num_byte_to_write -= count;
            num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
            num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;

            spi_flash_page_write(pbuffer,write_addr, count);
            write_addr += count;
            pbuffer += count;

            while(num_of_page--){
                spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
                write_addr += SPI_FLASH_PAGE_SIZE;
                pbuffer += SPI_FLASH_PAGE_SIZE;
            }

            if(0 != num_of_single)
                spi_flash_page_write(pbuffer,write_addr,num_of_single);
        }
    }
}
/*!
    \brief      read a block of data from the flash
    \param[in]  pbuffer: pointer to the buffer that receives the data read from the flash
    \param[in]  read_addr: flash's internal address to read from
    \param[in]  num_byte_to_read: number of bytes to read from the flash
    \param[out] none
    \retval     none
*/
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read)
{
    if (USE_SPI_IO == 1)
    {
        read_addr=read_addr+ONCHIP_FLASH_OFFSET;
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_ON;
        }
        else
        {
            GPIO_SPI_CS_ON;
        }
        /* send "read from memory " instruction */
        SPI_WriteByte(0x0B);

        /* send read_addr high nibble address byte to read from */
        SPI_WriteByte(read_addr >> 16);
        /* send read_addr medium nibble address byte to read from */
        SPI_WriteByte(read_addr >> 8);
        /* send read_addr low nibble address byte to read from */
        SPI_WriteByte(read_addr);

        SPI_WriteByte(00);
        /* while there is data to be read */
        for(int i = 0; i < num_byte_to_read; i++) {
            *(pbuffer+i) = SPI_ReadByte();
        }
        if(USE_ONCHIP_FLASH==1)
        {
            SPI_CS_OFF;
        }
        else
        {
            GPIO_SPI_CS_OFF;
        }
    }
    else
    {
        GPIO_SPI_CS_ON;
        /* send "read from memory " instruction */
        GPIO_SPI_WriteByte(0x0B);

        /* send read_addr high nibble address byte to read from */
        GPIO_SPI_WriteByte(read_addr >> 16);
        /* send read_addr medium nibble address byte to read from */
        GPIO_SPI_WriteByte(read_addr >> 8);
        /* send read_addr low nibble address byte to read from */
        GPIO_SPI_WriteByte(read_addr);

        GPIO_SPI_WriteByte(00);
        /* while there is data to be read */
        for(int i = 0; i < num_byte_to_read; i++) {
            *(pbuffer+i) = GPIO_SPI_ReadByte();
        }
        GPIO_SPI_CS_OFF;
    }
}


